﻿
    using System;
    using System.Reflection;
    using System.Windows.Media;
namespace WCYCReader.ImageTool
{
    public class ImageBase
    {
        private bool _isLoaded;
        private int _pixelHeight;
        private byte[] _pixels;
        private int _pixelWidth;

        public ImageBase()
        {
        }

        public ImageBase(ImageBase other)
        {
            Contract.Requires<ArgumentNullException>(other != null, "Other image cannot be null.");
            Contract.Requires<ArgumentException>(other.IsLoaded, "Other image has not been loaded.");
            Contract.Ensures(this.IsLoaded);
            byte[] pixels = other.Pixels;
            this._pixelWidth = other.PixelWidth;
            this._pixelHeight = other.PixelHeight;
            this._pixels = new byte[pixels.Length];
            Array.Copy(pixels, this._pixels, pixels.Length);
            this._isLoaded = other.IsLoaded;
        }

        public ImageBase(int width, int height)
        {
            Contract.Requires<ArgumentException>(width >= 0, "Width must be greater or equals than zero.");
            Contract.Requires<ArgumentException>(height >= 0, "Height must be greater or equals than zero.");
            Contract.Ensures(this.IsLoaded);
            this._pixelWidth = width;
            this._pixelHeight = height;
            this._pixels = new byte[(this.PixelWidth * this.PixelHeight) * 4];
            this._isLoaded = true;
        }

        [ContractVerification(false)]
        internal static void Crop(ImageBase source, ImageBase target, Rectangle bounds)
        {
            Contract.Requires<ArgumentNullException>(source != null, "Source image cannot be null.");
            Contract.Requires<ArgumentException>(source.IsLoaded, "Source image has not been loaded.");
            Contract.Requires<ArgumentNullException>(target != null, "Target image cannot be null.");
            Guard.GreaterThan<int>(bounds.Width, 0, "bounds", "Width of the rectangle must be greater than zero.");
            Guard.GreaterThan<int>(bounds.Height, 0, "bounds", "Height of the rectangle must be greater than zero.");
            if ((bounds.Right > source.PixelWidth) || (bounds.Bottom > source.PixelHeight))
            {
                throw new ArgumentException("Rectangle must be in the range of the image's dimension.", "bounds");
            }
            byte[] pixels = source.Pixels;
            byte[] destinationArray = new byte[(bounds.Width * bounds.Height) * 4];
            int top = bounds.Top;
            for (int i = 0; top < bounds.Bottom; i++)
            {
                Array.Copy(pixels, (int) (((top * source.PixelWidth) + bounds.Left) * 4), destinationArray, (int) ((i * bounds.Width) * 4), (int) (bounds.Width * 4));
                top++;
            }
            target.SetPixels(bounds.Width, bounds.Height, destinationArray);
        }

        private static void FlipX(ImageBase image)
        {
            Contract.Requires<ArgumentNullException>(image != null, "Image cannot be null.");
            Contract.Requires<ArgumentException>(image.IsLoaded, "Other image has not been loaded.");
            int index = 0;
            int num2 = 0;
            byte[] pixels = image.Pixels;
            for (int i = 0; i < (image.PixelHeight / 2); i++)
            {
                for (int j = 0; j < image.PixelWidth; j++)
                {
                    index = ((i * image.PixelWidth) + j) * 4;
                    byte num5 = pixels[index];
                    byte num6 = pixels[index + 1];
                    byte num7 = pixels[index + 2];
                    byte num8 = pixels[index + 3];
                    num2 = ((((image.PixelHeight - i) - 1) * image.PixelWidth) + j) * 4;
                    pixels[index] = pixels[num2];
                    pixels[index + 1] = pixels[num2 + 1];
                    pixels[index + 2] = pixels[num2 + 2];
                    pixels[index + 3] = pixels[num2 + 3];
                    pixels[num2] = num5;
                    pixels[num2 + 1] = num6;
                    pixels[num2 + 2] = num7;
                    pixels[num2 + 3] = num8;
                }
            }
        }

        private static void FlipY(ImageBase image)
        {
            Contract.Requires<ArgumentNullException>(image != null, "Image cannot be null.");
            Contract.Requires<ArgumentException>(image.IsLoaded, "Other image has not been loaded.");
            int index = 0;
            int num2 = 0;
            byte[] pixels = image.Pixels;
            for (int i = 0; i < image.PixelHeight; i++)
            {
                for (int j = 0; j < (image.PixelWidth / 2); j++)
                {
                    index = ((i * image.PixelWidth) + j) * 4;
                    byte num5 = pixels[index];
                    byte num6 = pixels[index + 1];
                    byte num7 = pixels[index + 2];
                    byte num8 = pixels[index + 3];
                    num2 = ((((i * image.PixelWidth) + image.PixelWidth) - j) - 1) * 4;
                    pixels[index] = pixels[num2];
                    pixels[index + 1] = pixels[num2 + 1];
                    pixels[index + 2] = pixels[num2 + 2];
                    pixels[index + 3] = pixels[num2 + 3];
                    pixels[num2] = num5;
                    pixels[num2 + 1] = num6;
                    pixels[num2 + 2] = num7;
                    pixels[num2 + 3] = num8;
                }
            }
        }

        private static void Rotate180(ImageBase source, ImageBase target)
        {
            Contract.Requires(source != null);
            Contract.Requires(source.IsLoaded);
            Contract.Requires(target != null);
            Contract.Ensures(target.IsLoaded);
            int index = 0;
            int num2 = 0;
            byte[] pixels = source.Pixels;
            byte[] buffer2 = new byte[(source.PixelWidth * source.PixelHeight) * 4];
            for (int i = 0; i < source.PixelHeight; i++)
            {
                for (int j = 0; j < source.PixelWidth; j++)
                {
                    index = ((i * source.PixelHeight) + j) * 4;
                    num2 = ((((((source.PixelHeight - i) - 1) * source.PixelWidth) + source.PixelWidth) - j) - 1) * 4;
                    buffer2[num2] = pixels[index];
                    buffer2[num2 + 1] = pixels[index + 1];
                    buffer2[num2 + 2] = pixels[index + 2];
                    buffer2[num2 + 3] = pixels[index + 3];
                }
            }
            target.SetPixels(source.PixelWidth, source.PixelHeight, buffer2);
        }

        private static void Rotate270(ImageBase source, ImageBase target)
        {
            Contract.Requires(source != null);
            Contract.Requires(source.IsLoaded);
            Contract.Requires(target != null);
            Contract.Ensures(target.IsLoaded);
            int index = 0;
            int num2 = 0;
            byte[] pixels = source.Pixels;
            byte[] buffer2 = new byte[(source.PixelWidth * source.PixelHeight) * 4];
            for (int i = 0; i < source.PixelHeight; i++)
            {
                for (int j = 0; j < source.PixelWidth; j++)
                {
                    index = ((i * source.PixelWidth) + j) * 4;
                    num2 = ((((source.PixelWidth - j) - 1) * source.PixelHeight) + i) * 4;
                    buffer2[num2] = pixels[index];
                    buffer2[num2 + 1] = pixels[index + 1];
                    buffer2[num2 + 2] = pixels[index + 2];
                    buffer2[num2 + 3] = pixels[index + 3];
                }
            }
            target.SetPixels(source.PixelHeight, source.PixelWidth, buffer2);
        }

        private static void Rotate90(ImageBase source, ImageBase target)
        {
            Contract.Requires(source != null);
            Contract.Requires(source.IsLoaded);
            Contract.Requires(target != null);
            Contract.Ensures(target.IsLoaded);
            int index = 0;
            int num2 = 0;
            byte[] pixels = source.Pixels;
            byte[] buffer2 = new byte[(source.PixelWidth * source.PixelHeight) * 4];
            for (int i = 0; i < source.PixelHeight; i++)
            {
                for (int j = 0; j < source.PixelWidth; j++)
                {
                    index = ((i * source.PixelWidth) + j) * 4;
                    num2 = ((((j + 1) * source.PixelHeight) - i) - 1) * 4;
                    buffer2[num2] = pixels[index];
                    buffer2[num2 + 1] = pixels[index + 1];
                    buffer2[num2 + 2] = pixels[index + 2];
                    buffer2[num2 + 3] = pixels[index + 3];
                }
            }
            target.SetPixels(source.PixelHeight, source.PixelWidth, buffer2);
        }

        public void SetPixels(int width, int height, byte[] pixels)
        {
            Contract.Requires<ArgumentException>(width >= 0, "Width must be greater than zero.");
            Contract.Requires<ArgumentException>(height >= 0, "Height must be greater than zero.");
            Contract.Requires<ArgumentNullException>(pixels != null, "Pixels cannot be null.");
            Contract.Ensures(this.IsLoaded);
            if (pixels.Length != ((width * height) * 4))
            {
                throw new ArgumentException("Pixel array must have the length of width * height * 4.", "pixels");
            }
            this._pixelWidth = width;
            this._pixelHeight = height;
            this._pixels = pixels;
            this._isLoaded = true;
        }

        internal static void Transform(ImageBase source, ImageBase target, RotationType rotationType, FlippingType flippingType)
        {
            Contract.Requires<ArgumentNullException>(source != null, "Source image cannot be null.");
            Contract.Requires<ArgumentException>(source.IsLoaded, "Source image has not been loaded.");
            Contract.Requires<ArgumentNullException>(target != null, "Target image cannot be null.");
            switch (rotationType)
            {
                case RotationType.None:
                {
                    byte[] pixels = source.Pixels;
                    byte[] destinationArray = new byte[pixels.Length];
                    Array.Copy(pixels, destinationArray, pixels.Length);
                    target.SetPixels(source.PixelWidth, source.PixelHeight, destinationArray);
                    break;
                }
                case RotationType.Rotate90:
                    Rotate90(source, target);
                    break;

                case RotationType.Rotate180:
                    Rotate180(source, target);
                    break;

                case RotationType.Rotate270:
                    Rotate270(source, target);
                    break;

                default:
                    throw new InvalidOperationException();
            }
            switch (flippingType)
            {
                case FlippingType.FlipX:
                    FlipX(target);
                    return;

                case FlippingType.FlipY:
                    FlipY(target);
                    return;
            }
        }

        [Pure]
        public Rectangle Bounds
        {
            get
            {
                return new Rectangle(0, 0, this.PixelWidth, this.PixelHeight);
            }
        }

        public bool IsLoaded
        {
            get
            {
                return this._isLoaded;
            }
        }

        [Pure]
        public Color this[int x, int y]
        {
            get
            {
                Contract.Requires<InvalidOperationException>(this.IsLoaded, "Image is not loaded.");
                Contract.Requires<ArgumentException>((x >= 0) && (x < this.PixelWidth), "X must be in the range of the image.");
                Contract.Requires<ArgumentException>((y >= 0) && (y < this.PixelHeight), "Y must be in the range of the image.");
                Contract.Ensures(this.IsLoaded);
                int index = ((y * this.PixelWidth) + x) * 4;
                Color color = new Color();                
                color.R=(this._pixels[index]);
                color.G=(this._pixels[index + 1]);
                color.B=(this._pixels[index + 2]);
                color.A=(this._pixels[index + 3]);
                return color;
            }
            set
            {
                Contract.Requires<InvalidOperationException>(this.IsLoaded, "Image is not loaded.");
                Contract.Requires<ArgumentException>((x >= 0) && (x < this.PixelWidth), "X must be in the range of the image.");
                Contract.Requires<ArgumentException>((y >= 0) && (y < this.PixelHeight), "Y must be in the range of the image.");
                Contract.Ensures(this.IsLoaded);
                int index = ((y * this.PixelWidth) + x) * 4;
                this._pixels[index] = value.R;
                this._pixels[index + 1] = value.G;
                this._pixels[index + 2] = value.B;
                this._pixels[index + 3] = value.A;
            }
        }

        public int PixelHeight
        {
            get
            {
                Contract.Ensures(!this.IsLoaded || (Contract.Result<int>() >= 0));
                return this._pixelHeight;
            }
        }

        [Pure]
        public byte[] Pixels
        {
            get
            {
                Contract.Ensures(!this.IsLoaded || (Contract.Result<byte[]>() != null));
                return this._pixels;
            }
        }

        public int PixelWidth
        {
            get
            {
                Contract.Ensures(!this.IsLoaded || (Contract.Result<int>() >= 0));
                return this._pixelWidth;
            }
        }
    }
}

